package edge.display.backend.Utils;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实体类工具类
 *
 * @author Amane Hayaashi
 * @date 2020/10/24
 * @since 1.0
 */

public class BeanUtils {

    public static <T> Object copyProps(final T copyFrom, final Collection<T> copyTo, final String identifier) {
        if (copyTo.size() == 0) {
            return copyFrom;
        }
        if (Objects.isNull(copyFrom)) {
            return copyTo.toArray()[0];
        }
        T copyToT = findHomogeneous(copyFrom, copyTo, identifier);
        if (Objects.nonNull(copyToT)) {
            copyTo.remove(copyToT);
            copyProps(copyFrom, copyToT);
            copyTo.add(copyToT);
            return copyToT;
        } else {
            return copyFrom;
        }
    }

    public static <T> T findHomogeneous(final T target, final Collection<T> set, final String identifier) {
        return set.stream().filter(t -> isHomogeneous(t, target, identifier)).findFirst().orElse(null);
    }

    private static <T> boolean isHomogeneous(final T t1, final T t2, String identifier) {
        return isHomogeneous(new BeanWrapperImpl(t1), new BeanWrapperImpl(t2), identifier);
    }

    private static boolean isHomogeneous(final BeanWrapper b1, final BeanWrapper b2, String identifier) {
        return Objects.equals(b1.getPropertyValue(identifier), b2.getPropertyValue(identifier));
    }

    private static <T> void copyProps(final T copyFrom, final T copyTo) {
        final BeanWrapper wrapperCopyTo = new BeanWrapperImpl(copyTo);
        Map<String, Object> notNulls = getNotNullProperties(copyFrom);
        Iterator<Map.Entry<String, Object>> iterator = notNulls.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            String s = entry.getKey();
            if (entry.getValue() instanceof List) {
                List<Object> orgList = (List<Object>) wrapperCopyTo.getPropertyValue(s);
                List<Object> newList = (List<Object>) notNulls.get(s);
                if (Objects.nonNull(orgList)) {
                    orgList.addAll(newList);
                } else {
                    orgList = newList;
                }
                wrapperCopyTo.setPropertyValue(s, orgList);
                iterator.remove();
            }
        }
        wrapperCopyTo.setPropertyValues(notNulls);
    }

    private static Map<String, Object> getNotNullProperties(Object src) {
        final BeanWrapper srcWrapper = new BeanWrapperImpl(src);
        return Arrays.stream(srcWrapper.getPropertyDescriptors())
                .filter(s -> {
                    String name = s.getName();
                    return !("class".equals(name) || isZero(srcWrapper.getPropertyValue(name)));
                })
                .collect(Collectors.toMap(
                        PropertyDescriptor::getName,
                        s -> Objects.requireNonNull(srcWrapper.getPropertyValue(s.getName()))
                        )
                );
    }

    private static boolean isZero(Object src) {
        try {
            return src == null || Double.parseDouble(src.toString()) == 0;
        } catch (Exception e) {
            return false;
        }
    }
}
